<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="text/javascript">
var aim;
P=-0.01;
I=-0.0008;
D=-0.00002;

var ierror=0;
var errorpre=0;

var cxt;
var canvas;
var width;
var height;

var x,y,eyex,eyey;
var carW=30;
var angle=0;
var v=15;va=0;//速度，角速度
var eyeDistance=carW/2+2;
var eyeSize=4;

function mainInit(){
	P=parseFloat(document.getElementById("input_P").value);
	I=parseFloat(document.getElementById("input_I").value);
	D=parseFloat(document.getElementById("input_D").value);
	v=parseFloat(document.getElementById("input_V").value);
	aim=parseFloat(document.getElementById("input_Aim").value);
	canvas=document.getElementById("mainCanvas");
	cxt=canvas.getContext("2d");
	width=canvas.width;
	height=canvas.height;
	x=width/3;
	y=height/3-10;
	angle=va=errorpre=ierror=0;
}

function circle(x,y,r,cxt){
	cxt.beginPath();
	cxt.arc(x,y,r,0,6.29,true);
	cxt.closePath();
	cxt.stroke();
}
function drawBackground(){
	cxt.strokeStyle="blue";
	cxt.lineWidth=10;
	cxt.strokeRect(0,0,width,height);
	cxt.strokeRect(width/3,height/3,width/3,height/3);
	circle(width/3,height/2,height/6,cxt);
	circle(width*2/3,height/2,height/6,cxt);
	cxt.lineWidth=2;
}
function drawCar(){
	cxt.lineWidth=4;
	cxt.strokeStyle="yellowgreen";
	circle(x,y,carW/2,cxt);
	circle(eyex,eyey,eyeSize,cxt);
}
function drive(){
	angle+=va;
	x+=v*Math.cos(angle);
	y+=v*Math.sin(angle);
	x=(x+width)%width;y=(y+height)%height;
	eyex=x+eyeDistance*Math.cos(angle);
	eyey=y+eyeDistance*Math.sin(angle);
	eyex=(eyex+width)%width;eyey=(eyey+height)%height;
}
function disp(value){
	cxt.lineWidth=1;
	cxt.strokeStyle="red";
	cxt.strokeText("采集值："+value,10,40,320);
}
function control(){
	var data=cxt.getImageData(eyex-eyeSize,eyey-eyeSize,eyeSize*2,eyeSize*2);
	var value=0;
	for(var i=0;i<data.data.length;i+=4){
		value+=data.data[i+2];
	}
	value/=data.data.length;
	disp(Math.round(value));
	//console.log("l:"+data.data.length+";v:"+value);
	var verror=value-aim;//误差，越暗值越大
	ierror+=verror;
	var derror=verror-errorpre;//负数表示由暗到亮，反之由亮到暗
	va=verror*P+ierror*I+derror*D;
	errorpre=verror;
}
function execute(){
	cxt.clearRect(0,0,width,height);
	drawBackground();
	drive();
	control();
	drawCar();
}
</script>
</head>
<body style="margin:80px 120px">
<form> 比例控制系数: <input id="input_P" value="-0.006"/>
积分控制系数： <input id="input_I" value="-0.0008"/>
微分控制系数： <input id="input_D" value="-0.00002"/> 
<br />
控制量： <input id="input_Aim" value="24"/>
<br/>
小车前进速度： <input id="input_V" value="2"/>
<br />
<button type="button" id="submit" onclick="mainInit()">提交参数</button>
</form>
<canvas id="mainCanvas" width="640" height="480">抱歉，此浏览器不支持HTML5</canvas>
<script type="text/javascript"> mainInit();setInterval("execute()",13);</script>
<p>
本頁面演示了運用PID算法控制的循跡小車。當小車的“眼” 看到藍色時，知道自己在藍色線上，於是左轉。反之，若眼看到白色，則右轉。於是，小車始終沿線的邊緣運動。輸入量是“眼”看到的灰度值，輸出量是角速度，控制方法為PID控制。
</p>
<p>
待辦：這裡都沒有考慮到小車的質量……而且控制量也應當為電機的電流、力矩之類，而不是就直接就控制角速度了。還應當考慮傳感器的誤差和干擾。總之這個仿真還是不夠真實。
</p>
</body>
</html>